﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using IMModel.Domain;
using System.Data.Linq;

namespace DataAccessLayer.Admin.Filters
{
    public class AnswerLogFilterGenerator : FilterGeneratorBase
    {
        private AnswerLogFilterGenerator() { }
        public static readonly AnswerLogFilterGenerator I = new AnswerLogFilterGenerator();

        /// <summary>
        /// Фильтрация по значению
        /// </summary>
        /// <param name="volume"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> Volume(object volume, DTO.ConditionTypes ConditionType)
        {
            var param = Expression.Parameter(typeof(Answer), "c");

            Expression exp = Filter.GetCompareOperator(Expression.Property(param, "Volume"),
                Expression.Constant((double)volume), ConditionType);

            var l = Expression.Lambda<Func<Answer, bool>>(exp, param);
            return l.Compile();
        }

        /// <summary>
        /// Фильтрация по операции
        /// </summary>
        /// <param name="operationName"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> Operation(object operationName, DTO.ConditionTypes ConditionType)
        {
            DTO.StateObject operation = (DTO.StateObject)operationName;

            var param = Expression.Parameter(typeof(Answer), "c");

            Expression resultExpression = null;

            switch (operation)
            {
                case DTO.StateObject.Created:
                    {
                        var parentAns_prop = Expression.Property(param, "Answer1");
                        var checkParentNull = Expression.Equal(parentAns_prop, Expression.Constant(null));

                        var isDeleted_prop = Expression.Property(param, "IsDeleted");
                        var checkDeletedFalse = Expression.IsFalse(isDeleted_prop);

                        var checkParentNullLambda = Expression.Lambda<Func<Answer, bool>>(checkParentNull, param);
                        var checkDeletedFalseLambda = Expression.Lambda<Func<Answer, bool>>(checkDeletedFalse, param);
                        resultExpression = Expression.AndAlso(checkParentNullLambda.Body, checkDeletedFalseLambda.Body);
                        resultExpression = CheckNotContains(resultExpression, ConditionType);

                        var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, checkParentNullLambda.Parameters[0]);
                        return l.Compile();
                    }

                case DTO.StateObject.Deleted:
                    {
                        var isDeleted_prop = Expression.Property(param, "IsDeleted");
                        resultExpression = Expression.IsTrue(isDeleted_prop);
                        resultExpression = CheckNotContains(resultExpression, ConditionType);

                        var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, param);
                        return l.Compile();
                    }

                case DTO.StateObject.Updated:
                    {
                        var parentAns_prop = Expression.Property(param, "Answer1");
                        var checkParentNotNull = Expression.NotEqual(parentAns_prop, Expression.Constant(null));

                        var isDeleted_prop = Expression.Property(param, "IsDeleted");
                        var checkDeletedFalse = Expression.IsFalse(isDeleted_prop);

                        var checkChildsLambda = Expression.Lambda<Func<Answer, bool>>(checkParentNotNull, param);
                        var checkDeletedFalseLambda = Expression.Lambda<Func<Answer, bool>>(checkDeletedFalse, param);
                        resultExpression = Expression.AndAlso(checkChildsLambda.Body, checkDeletedFalseLambda.Body);
                        resultExpression = CheckNotContains(resultExpression, ConditionType);

                        var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, checkChildsLambda.Parameters[0]);
                        return l.Compile();
                    }
                default:
                        throw new Exception("Данная операция сравнения не реализована: " + operation.ToString());
            }
        }

        /// <summary>
        /// Фильтрация по сотруднику
        /// </summary>
        /// <param name="LastName"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> Person(object LastName, DTO.ConditionTypes ConditionType)
        {
            LastName = LastName.ToString().ToLower();

            var param = Expression.Parameter(typeof(Answer), "c");
            var resp_prop = Expression.Property(param, "Respondent");
            var pers_prop = Expression.Property(resp_prop, "Person");
            var LastName_prop = Expression.Property(pers_prop, "LastName");

            var ToLower_method = Expression.Call(LastName_prop,
                typeof(string).GetMethod("ToLower", Type.EmptyTypes));

            Expression resultExpression = Expression.Call(ToLower_method,
                typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(LastName));
            resultExpression = CheckNotContains(resultExpression, ConditionType);

            var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, param);

            return l.Compile();
        }

        /// <summary>
        /// Фильтрация по имени пользователя
        /// </summary>
        /// <param name="name"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> UserName(object name, DTO.ConditionTypes ConditionType)
        {
            name = name.ToString().ToLower();

            var param = Expression.Parameter(typeof(Answer), "c");
            var user_prop = Expression.Property(param, "UserName");

            var ToLower_method = Expression.Call(user_prop,
                typeof(string).GetMethod("ToLower", Type.EmptyTypes));

            Expression resultExpression = Expression.Call(ToLower_method,
                typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(name));
            resultExpression = CheckNotContains(resultExpression, ConditionType);

            var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, param);

            return l.Compile();
        }

        /// <summary>
        /// Фильтрация по отделу
        /// </summary>
        /// <param name="Abbriviation_or_Name"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> Department(object Abbriviation_or_Name, DTO.ConditionTypes ConditionType)
        {
            Abbriviation_or_Name = Abbriviation_or_Name.ToString().ToLower();

            var param = Expression.Parameter(typeof(Answer), "c");
            var resp_prop = Expression.Property(param, "Respondent");
            var dep_term_prop = Expression.Property(resp_prop, "DepartmentTerm");
            var dep_prop = Expression.Property(dep_term_prop, "Department");
            var name_prop = Expression.Property(dep_prop, "Name");

            var abbr_prop = Expression.Property(dep_prop, "Abbriviation");

            var ToLower_name_method = Expression.Call(name_prop,
                typeof(string).GetMethod("ToLower", Type.EmptyTypes));

            var Contains_name_method = Expression.Call(ToLower_name_method,
                typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(Abbriviation_or_Name));

            var ToLower_abbr_method = Expression.Call(abbr_prop,
                typeof(string).GetMethod("ToLower", Type.EmptyTypes));

            var Contains_abbr_method = Expression.Call(ToLower_abbr_method,
                typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(Abbriviation_or_Name));

            var checkNameLambda = Expression.Lambda<Func<Answer, bool>>(Contains_name_method, param);
            var checkAbbrLambda = Expression.Lambda<Func<Answer, bool>>(Contains_abbr_method, param);
            Expression resultExpression = Expression.OrElse(checkNameLambda.Body, checkAbbrLambda.Body);
            resultExpression = CheckNotContains(resultExpression, ConditionType);

            var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, checkNameLambda.Parameters[0]);

            return l.Compile();
        }

        /// <summary>
        /// Фильтрация по имени показателя
        /// </summary>
        /// <param name="name"></param>
        /// <param name="ConditionType"></param>
        /// <returns></returns>
        public Func<Answer, bool> Characteristic(object name, DTO.ConditionTypes ConditionType)
        {
            name = name.ToString().ToLower();

            var param = Expression.Parameter(typeof(Answer), "c");
            var charTerm_prop = Expression.Property(param, "CharacteristicTerm");
            var char_prop = Expression.Property(charTerm_prop, "Characteristic");
            var charName_prop = Expression.Property(char_prop, "Name");

            var ToLower_method = Expression.Call(charName_prop,
                typeof(string).GetMethod("ToLower", Type.EmptyTypes));

            Expression resultExpression = Expression.Call(ToLower_method,
                typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(name));
            resultExpression = CheckNotContains(resultExpression, ConditionType);

            var l = Expression.Lambda<Func<Answer, bool>>(resultExpression, param);

            return l.Compile();
        }
    }
}
